package cate.game.pvp.guildwar;

import cate.common.table.d.GDGuildWar;
import cate.common.table.d.GDMail;
import cate.common.table.d.GDOperation;
import cate.common.util.TimeTool;
import cate.common.util.XT;
import cate.game.db.facade.KvLoader;
import cate.game.db.mongo.kv.KvMongo;
import cate.game.framework.ModuleMan;
import cate.game.mail.po.MailBuilder;
import cate.game.pvp.guildwar.data.GWGuildProfile;
import cate.game.pvp.guildwar.data.base.GWMatchGroup;
import cate.game.pvp.guildwar.data.base.GuildWarKV;
import cate.game.pvp.guildwar.data.msg.GWBaseInnerResp;
import cate.game.pvp.guildwar.data.msg.GWSideApplyInnerReq;
import cate.game.pvp.guildwar.data.msg.GWSideInnerUpdate;
import cate.game.pvp.guildwar.data.msg.GWTopGuildRwdReq;
import cate.game.res.MixRes;
import cate.game.role.mail.Mail;
import cate.game.role.res.guild.po.GuildPO;
import cate.game.role.res.guild.po.member.GuildMemberDetailPO;
import cate.game.util.IntervalCounter;
import lombok.Getter;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.function.Consumer;

@Getter
public class GWDataManager extends ModuleMan {

	private GuildWarKV kv;

	private IntervalCounter minTrigger = new IntervalCounter(60);

	private IntervalCounter saveTrigger = new IntervalCounter(3600);

	@Getter
	private boolean dataReady;

	@Override
	public void initDependent() {
		this.kv = new KvLoader<>(game, GuildWarKV.class, KvMongo.KEY_GUILD_WAR_GAME).getBySrvId();

		checkStart();
	}

	@Override
	public void shutdown() {
		super.shutdown();
		save();
	}

	private void checkStart() {
		if (game.getOpenDay() >= GDGuildWar.OPEN_DAY_MIN) {
			boolean start = kv.timeTable.checkStart(game.table.guildWar.time);
			if (start) {
				log.info("游戏服开启了一场[公会战]");
				onPeriodChange();
			}
		}
	}

	@Override
	public void onDaySpan() {
		kv.onDaySpan();
		checkStart();
	}

	private void save(){
		game.db.kv.save(this.kv);
	}


	public void tick() {
		boolean change = kv.timeTable.tick();
		if (change) {
			onPeriodChange();
		}
		if (this.minTrigger.trigger()) {
			handleSign();
			sendSideApply();
			syncPoint();
		}
		if (this.saveTrigger.trigger()) {
			save();
		}
	}

	public void onPeriodChange() {
		final byte period = kv.timeTable.period;
		switch (period) {
			case GDGuildWar.Period.SIGN_UP:
				pickGuild();
				break;
		}
		// 通知参与公会战的公会做这个阶段该做的事情
		forMatchGuilds(g -> {
			g.war.onPeriodChange(period);
		});
	}

	// 选拔本服具有参赛资格的公会
    private void pickGuild() {
        List<GWGuildProfile> signUpGuilds = new ArrayList<>();
        List<GuildPO> realGuilds = game.res.guild.getGuildList();
        realGuilds.sort(
                Comparator.comparing((GuildPO a) -> -a.basic.level)
                        .thenComparing(a -> -a.basic.power)
                        .thenComparing(a -> -a.basic.memberNum));
        for (GuildPO guild : realGuilds) {
            // 检测公会等级
            if (guild.basic.level < GDGuildWar.GUILD_LEVEL_MIN) {
                log.info("公会 [{}] 因为公会等级不足，未能入选本次公会战", guild.basic.guildName);
                continue;
            }
            // 单服最多挑选20个服
            if (signUpGuilds.size() >= GDGuildWar.GUILD_PICK_MAX) {
                log.info("公会 [{}] 因当前报名公会已满{}个,未能入选本次公会战", guild.basic.guildName, GDGuildWar.GUILD_PICK_MAX);
                break;
            }
            int activeNum = 0;
            // 检测活跃人数
			for (GuildMemberDetailPO m : guild.member.getCopyMembers()) {
				if ((System.currentTimeMillis() - m.it.activeTime) / TimeTool.TimeCons.DAY <= GDGuildWar.OFFLINE_DAY_MAX) {
					activeNum++;
					if (activeNum >= GDGuildWar.ACTIVE_MEMBER_MIN) {
						signUpGuilds.add(GWGuildProfile.of(game.config.srvId, guild));
						log.info("公会 [{}] 成功报名本次公会战", guild.basic.guildName);
						break;
					}
				}
			}
			if (activeNum < GDGuildWar.ACTIVE_MEMBER_MIN) {
				log.info("公会 [{}] 因为活跃人数不足，未能入选本次公会战", guild.basic.guildName);
			}
		}
        kv.signUpGuilds = signUpGuilds;
		handleSign();
	}

	private void handleSign() {
		if (kv.timeTable.period == GDGuildWar.Period.SIGN_UP && !kv.sign && XT.isNotBlank(kv.signUpGuilds)) {
			boolean success = game.pvp.guildWar.getMessagingModule().sign(kv.signUpGuilds);
			if (success) {
				kv.sign = true;
			}
		}
	}

	private void sendSideApply() {
		if (kv.timeTable.period == GDGuildWar.Period.MATCH) {
			forMatchGuilds(g -> {
				if (!g.war.pass() && !g.war.fightDataReady()) {
					GWSideApplyInnerReq apply = GWSideApplyInnerReq.of(g.war);
					if (g.war.field.b.profile.srvId == game.config.srvId) {
						handleSideApply(apply);
					} else {
						game.pvp.guildWar.getMessagingModule().applySide(apply);
					}
				}
			});
		}
	}

	private void syncPoint(){
		if (kv.timeTable.period == GDGuildWar.Period.SETTLE_RWD) {
			forMatchGuilds(g -> {
				if (!g.war.synPoint) {
					g.war.trySynPoint();
				}
			});
		}
	}


	//处理公会战基础数据
	public void updateBase(GWBaseInnerResp resp) {
		dataReady = true;
		boolean seasonChange = kv.index != resp.index;
		kv.index = resp.index;
		kv.startTime = resp.startTime;
		kv.endTime = resp.endTime;
		if (XT.isNotBlank(resp.matchList)) {
			handleMatch(resp.matchList);
		}
		if (resp.rankMap != null) {
			forGuilds(g -> {
				int rank = resp.rankMap.getOrDefault(g.uid, -1);
				g.war.updateRank(rank);
			});
		}

		if (seasonChange) {
			forGuilds(g -> g.war.onSeasonChange());
		}
	}


	//处理匹配信息
	private void handleMatch(List<GWMatchGroup> matchList) {
		// 如果已经收到匹配息那么就不处理了
		if (kv.match || kv.timeTable.period != GDGuildWar.Period.MATCH) {
			return;
		}
		log.info("接收到cross服的公会战对阵信息,共有{}组", matchList.size());
		for (GWMatchGroup matchData : matchList) {
			if (matchData.a.srvId == game.config.srvId) {
				doHandleMatch(matchData.a, matchData.b);
			}
			if (matchData.b != null && matchData.b.srvId == game.config.srvId) {
				doHandleMatch(matchData.b, matchData.a);
			}
		}
		kv.match = true;
	}

	//处理一方数据申请
	public void handleSideApply(GWSideApplyInnerReq data) {
		if (kv.timeTable.period != GDGuildWar.Period.MATCH) {
			return;
		}
		GuildPO guild = game.res.guild.getGuild(data.tarGuildUid);
		if (guild == null) {
			return;
		}
		sendSideUpdate(GWSideInnerUpdate.of(guild.war));
	}

	//处理一方数据同步
	public void handleSideUpdate(GWSideInnerUpdate data){
		if (kv.timeTable.period != GDGuildWar.Period.MATCH && kv.timeTable.period != GDGuildWar.Period.FIGHT) {
			return;
		}
		GuildPO guild = game.res.guild.getGuild(data.tarGuildUid);
		if (guild == null) {
			return;
		}
		guild.war.handleOtherSide(data);
	}

	public void handleTopGuildRwd(GWTopGuildRwdReq req) {
		GuildPO guild = game.res.guild.getGuild(req.guildUid);
		if (guild == null) {
			return;
		}
		for (GuildMemberDetailPO member : guild.member.getCopyMembers()) {
			Mail mail = new MailBuilder().setContentId(GDMail.Tid.TOP_GUILD_RWD).setOperation(GDOperation.GUILD_WAR_TOP_GUILD).
					setReward(new MixRes(GDGuildWar.TOP_GUILD_SEASON_RWD_STR)).build();
			game.mail.send(member.it.uid, mail);
		}
	}

	/** 通知匹配成功 */
	private void doHandleMatch(GWGuildProfile chose, GWGuildProfile enemy) {
		GuildPO guild = game.res.guild.getGuild(chose.uid);
		if (guild == null) {
			log.info("公会[{}]成功入选本次公会战 但是竟然解散了！", chose.name);
			return;
		}
		log.info("公会[{}]成功入选本次公会战", guild.basic.guildName);
		guild.war.onMatch(chose, enemy);
	}

	/** 同步一方数据 */
	public void sendSideUpdate(GWSideInnerUpdate data) {
		if (data.tarSrvId == game.config.srvId) {
			handleSideUpdate(data);
		} else {
			game.pvp.guildWar.getMessagingModule().sendSideUpdate(data);
		}
	}

	private void forGuilds(Consumer<GuildPO> consumer) {
		for (GuildPO guild : game.res.guild.getGuildList()) {
			consumer.accept(guild);
		}
	}

	private void forMatchGuilds(Consumer<GuildPO> consumer){
		for (GuildPO guild : game.res.guild.getGuildList()) {
			if(guild.war.match){
				consumer.accept(guild);
			}
		}
	}
}
